package lmscript.postscript.syntax.stack;

import java.util.EmptyStackException;
import java.util.Vector;

import lmscript.postscript.syntax.PSMark;
import lmscript.postscript.syntax.PSObject;

public class PSStack {

	private Vector<PSObject> elements;
	private int mark = -1;

	public PSStack() {
		this.elements = new Vector<PSObject>();
	}

	/** Discard top element */
	public synchronized PSObject pop() {
		int len = this.elements.size();
		if (len <= 0) {
			throw new EmptyStackException();
		}
		PSObject obj = this.elements.get(len - 1);
		this.elements.remove(len - 1);
		return obj;
	}

	public synchronized PSObject peek() {
		return peek(0);
	}

	public synchronized PSObject peek(int top) {
		int len = this.elements.size();
		if (len <= 0) {
			throw new EmptyStackException();
		}
		return this.elements.get(len - 1 - top);
	}

	public synchronized void push(PSObject obj) {
		this.elements.add(obj);
	}

	public synchronized void dup() {
		PSObject obj = this.peek();
		this.push((PSObject) obj.clone());
	}

	public void exch() {
		PSObject e1 = this.pop();
		PSObject e2 = this.pop();
		this.push(e2);
		this.push(e1);
	}

	public void copy(int n) {
		int len = this.elements.size();
		if (len <= 0) {
			throw new EmptyStackException();
		}
		if (n < 0 || n >= len) {
			throw new IllegalArgumentException();
		}
		for (int i = len - n; i < len; i++) {
			this.push((PSObject) (this.elements.get(i)).clone());
		}
	}

	public void index(int index) {
		int len = this.elements.size();
		if (len <= 0) {
			throw new EmptyStackException();
		}
		if (index < 0 || index >= len) {
			throw new IllegalArgumentException();
		}
		this.push((PSObject) (this.elements.get(index)).clone());
	}

	public void roll() {

	}

	public void clear() {
		this.elements.removeAllElements();
	}

	public int count() {
		return size();
	}

	public void mark() {
		this.mark = size();
	}

	public void clearToMark() {
		int count = countToMark();
		if (count < 0) {
			PSObject top = peek();
			if (top != null && top instanceof PSMark) {
				pop();
			}
			return;
		}
		int from = size() - 1;
		int to = size() - count;
		for (int i = from; i >= to; i--) {
			this.elements.remove(i);
		}
	}

	public int countToMark() {
		int count = -1;
		for (int i = size() - 1; i >= 0; i--) {
			if (this.elements.get(i) instanceof PSMark) {
				break;
			}
			count++;
		}
		return count;
	}

	private int size() {
		return this.elements.size();
	}
}
